/*
 * Shape.cpp
 *
 *  Created on: 2010-9-6
 *      Author: wenjian
 */

#include "Shape.h"
#include "../WorkPage.h"
#include "../WorkLayer.h"
#include "../ControlLayer.h"
//#include "../LinkedWorkLayer.h"
#include "ControlPoint.h"
#include <bitset>
#include <globes.h>

using namespace Thk;
namespace S {

  unsigned long Shape::ClassId = hashCode("S::Shape");

  Shape::Shape(real x, real y, real w, real h):
    path(NULL), movingCursor(LoadCursor(NULL,IDC_SIZEALL)), mergeFlag(false) {

    setCoordinate(x, y);
    setWidth(w);
    setHeight(h);
    pen = new Gdiplus::Pen(Gdiplus::Color(255, 0, 0, 0));
    brush = new Gdiplus::SolidBrush(Gdiplus::Color(255, 255, 255, 255));
    controlPointSize = 8;
  }

  Shape::~Shape() {
    delete pen;
    delete brush;
    //LinkedWorkLayer* lnkedlayer = ((WorkPage*)(layer->getDrawPage()))->getLinkedWorkLayer();
    const vector<Element*>* cps = (const vector<Element*>*)controlPoints.getElements();
    for(vector<Element*>::const_iterator it=cps->begin(); it!=cps->end(); it++){
      //lnkedlayer->removeElement(*it);
      getLayer()->removeElement(*it);
      delete *it;
    }
    controlPoints.clear();
  }

  void Shape::buildControlPoint(){
    if(controlPoints.size()==0){
     // LinkedWorkLayer* lnkedlayer = ((WorkPage*)(layer->getDrawPage()))->getLinkedWorkLayer();

      for(int i=0; i<8; i++){
        ControlPoint* cp = new ControlPoint(i, this);
        controlPoints.add(cp);
        //cp->setLayer(getLayer());
        //lnkedlayer->addElement(cp);
        getLayer()->addElement(cp);
      }
    }else{
      for(int i=0; i<controlPoints.size(); i++){
        ControlPoint* cp =  (ControlPoint*)controlPoints.getElements()->at(i);
        cp->setVisible(true);
        //cp->redrawAll();
        cp->redrawIntersection();
      }
    }

    //初始化控制点数据
    real cw = controlPointSize;
    real cw2 = cw/2;
    real cx = x();
    real cy = y();
    real w = width();
    real h = height();
//    real cx = shapeRect.X;
//    real cy = shapeRect.Y;
//    real w = shapeRect.Width;
//    real h = shapeRect.Height;
    real w2 = w/2;
    real h2 = h/2;

    const vector<Element*>* cps = (const vector<Element*>*)controlPoints.getElements();
    ((ControlPoint*)cps->at(0))->setData(cx, cy, cx-cw2, cy-cw2, cw, cw);
    ((ControlPoint*)cps->at(1))->setData(cx+w2, cy, cx+w2-cw2, cy-cw2, cw, cw);
    ((ControlPoint*)cps->at(2))->setData(cx+w, cy, cx+w-cw2, cy-cw2, cw, cw);
    ((ControlPoint*)cps->at(3))->setData(cx+w, cy+h2, cx+w-cw2, cy+h2-cw2, cw, cw);
    ((ControlPoint*)cps->at(4))->setData(cx+w, cy+h, cx+w-cw2, cy+h-cw2, cw, cw);
    ((ControlPoint*)cps->at(5))->setData(cx+w2, cy+h, cx+w2-cw2, cy+h-cw2, cw, cw);
    ((ControlPoint*)cps->at(6))->setData(cx, cy+h, cx-cw2, cy+h-cw2, cw, cw);
    ((ControlPoint*)cps->at(7))->setData(cx, cy+h2, cx-cw2, cy+h2-cw2, cw, cw);
  }

  void Shape::hideControlPoint(){
    for(int i=0; i<controlPoints.size(); i++){
      ControlPoint* cp =  (ControlPoint*)controlPoints.getElements()->at(i);
      cp->redrawIntersection();
      cp->setVisible(false);
    }
  }

//  void Shape::drawControlPoints(Gdiplus::Graphics* g){
//    if(!isSelected()){
//      return;
//    }
//    const vector<Element*>* cps = controlPoints.getElements();
//    for(vector<Element*>::const_iterator it=cps->begin(); it!=cps->end(); it++){
//      if((*it)->isVisible()){
//        (*it)->draw(g);
//      }
//    }
//  }

  void Shape::adjustControlPointPosition(){
    const vector<Element*>* cps = controlPoints.getElements();
    for(vector<Element*>::const_iterator it=cps->begin(); it!=cps->end(); it++){
      layer->adjustElement(*it, 1, this);
      (*it)->redrawIntersection();
    }

//    for(int i=0; i<controlPoints.size(); i++){
//      Element* e = controlPoints.getElements()->at(i);
//      layer->adjustElement(controlPoints.getElements()->at(i), 1, this);
//      controlPoints[i]->redrawIntersection();
//    }
  }

//  inline bool Shape::trackEvent(const Event* e){
////    cout<<"Shape::trackEvent is 0 "<<this<<endl;
//    return Elements::trackEvent(e);
//
////    //跟踪控制点
////    if(isSelected()){
////      cout<<"Shape::trackEvent is 1 "<<this<<endl;
////      controlPoints.trackEvent(e);
////      cout<<"Shape::trackEvent is 2 "<<this<<endl;
////    }
//    return false;
//  }

//  Gdiplus::RectF* Shape::getBoundRect(Gdiplus::RectF* outBoundRect, real adjustVal){
//    Gdiplus::RectF* rect = this->getBoundRect();
//    outBoundRect->X = ceil(rect->X-adjustVal);
//    outBoundRect->Y = ceil(rect->Y-adjustVal);
//    outBoundRect->Width = ceil(rect->Width+adjustVal*2);
//    outBoundRect->Height = ceil(rect->Height+adjustVal*2);
//    //return Element::getBoundRect(outBoundRect, adjustVal);
//    return outBoundRect;
//  }

//  /**
//   * 返回包含元素所有可视内容的最大矩形，包括控制点，如果有
//   */
//  const Gdiplus::RectF* Shape::getBoundRect() {
//    if(!boundRect){
//      real x, y, w, h;
//      x = this->x();
//      y = this->y();
//      w = width();
//      h = height();
//
//      if(w<0){
//        x += w;
//        w = -w;
//      }
//      if(h<0){
//        y += h;
//        h = -h;
//      }
//      boundRect = new Gdiplus::RectF(x, y, w, h);
//    }
//    return boundRect;
//  }

  /**
   * 创建包含元素所有可视内容的最大矩形区域
   */
  void Shape::createBoundRect(){
    real x, y, w, h;
    x = this->x();
    y = this->y();
    w = width();
    h = height();
    if(w<0){
      x += w;
      w = -w;
    }
    if(h<0){
      y += h;
      h = -h;
    }
    if(boundRect){
        boundRect->X = x;
        boundRect->Y = y;
        boundRect->Width = w;
        boundRect->Height = h;
    }else{
      boundRect = new Gdiplus::RectF(x, y, w, h);
    }
  }

  /**
   * 检查是否与点(x, y)相交
   */
  bool Shape::intersects(real x, real y){
    const Gdiplus::RectF* boundrect = getBoundRect();
    return boundrect && boundrect->Contains(x, y)
        && path && (path->IsVisible(x,y) || path->IsOutlineVisible( x, y, pen));
  }

  bool Shape::intersects(Element* e){
    return Element::intersects(e);
  }

  /**
   * 改变大小
   */
  void Shape::adjustSize(real dx, real dy, int cpIndex){
    real x, y, w, h, ox, oy, ow, oh;
    x = ox = this->x();
    y = oy = this->y();
    w = ow = this->width();
    h = oh = this->height();
    switch(cpIndex){
      case 0:
        x += dx;
        y += dy;
        w -= dx;
        h -= dy;
        break;
      case 1:
        y += dy;
        h -= dy;
        break;
      case 2:
        y += dy;
        w += dx;
        h -= dy;
        break;
      case 3:
        w += dx;
        break;
      case 4:
        w += dx;
        h += dy;
        break;
      case 5:
        h += dy;
        break;
      case 6:
        x += dx;
        w -= dx;
        h += dy;
        break;
      case 7:
        x += dx;
        w -= dx;
        break;
    }

    redrawIntersection();
    setWidth(w);
    setHeight(h);
    setCoordinate(x, y);
    createPath();
    refreshControlPointCursor();
  }

  void Shape::refreshControlPointCursor(){
    real w = width();
    real h = height();
    const std::vector<ControlPoint*>* cps = (const std::vector<ControlPoint*>*)controlPoints.getElements();
    if(w>0 && h>0){
      cps->at(0)->setLowerLeftCursor();
      cps->at(4)->setLowerLeftCursor();
      cps->at(2)->setLowerRightCursor();
      cps->at(6)->setLowerRightCursor();
    }else if(w<0 && h>0){
      cps->at(0)->setLowerRightCursor();
      cps->at(4)->setLowerRightCursor();
      cps->at(2)->setLowerLeftCursor();
      cps->at(6)->setLowerLeftCursor();
    }else if(w>0 && h<0){
      cps->at(0)->setLowerRightCursor();
      cps->at(4)->setLowerRightCursor();
      cps->at(2)->setLowerLeftCursor();
      cps->at(6)->setLowerLeftCursor();
    }else if(w>0 && h<0){
      cps->at(0)->setLowerRightCursor();
      cps->at(4)->setLowerRightCursor();
      cps->at(2)->setLowerLeftCursor();
      cps->at(6)->setLowerLeftCursor();
    }else if(w<0 && h<0){
      cps->at(0)->setLowerLeftCursor();
      cps->at(4)->setLowerLeftCursor();
      cps->at(2)->setLowerRightCursor();
      cps->at(6)->setLowerRightCursor();
    }
  }

  bool Shape::event(const Event* e){
    return Element::event(e);
  }

  void Shape::mousePressEvent(const MouseEvent* e){
//    cout<<"Shape::mousePressEvent this is "<<this<<endl;
    //const KeySequence& kseq = e->getKeySequence();
    if(!isMerged()){
//      if(!kseq.test(Key_Shift) && !isSelected()){
//        getLayer()->getSelection()->clear(); //清除选择的元素
//      }
      setSelected(true);
    }

    setFocus();
    Element::mousePressEvent(e);
  }

  void Shape::mouseMoveEvent(const MouseEvent* e) {
//    cout<<"Shape::mouseMoveEvent this is "<<this<<endl;
    WorkPage* page = (WorkPage*)(layer->getDrawPage());
    if((page->getWorkMode() == WorkPage::SelectMode)){
      setCursor(&movingCursor);
    }
    return Element::mouseMoveEvent(e);
  }

  void Shape::mouseLeaveEvent(const MouseEvent* e) {
    cout<<"Shape::mouseLeaveEvent this is "<<this<<endl;
    resetCursor();
    return Element::mouseLeaveEvent(e);
  }


  void Shape::keyPressEvent(const KeyEvent* e){
//    cout<<"Shape.keyPressEvent, key is "<<e->getKey()<<endl;
  }

  void Shape::keyReleaseEvent(const KeyEvent* e){
//    cout<<"Shape.keyReleaseEvent, key is "<<e->getKey()<<endl;
  }

  void Shape::mouseDoubleClickEvent(const MouseEvent* e){
    //cout<<"Shape.mouseDoubleClickEvent, this is "<<this<<endl;
  }

  void Shape::selectEvent(const SelectEvent* e){
//    cout<<"Shape.selectEvent, "<<this<<" selected is "<<e->isSelected()<<endl;
    if(e->isSelected()){
      buildControlPoint();
    }else{
      hideControlPoint();
    }
  }

  void Shape::mouseEnterEvent(const MouseEvent* e){
    cout<<"Shape::mouseEnterEvent"<<endl;
  }

  void Shape::paintEvent(const PaintEvent* e){
    cout<<"Shape::paintEvent->getSource():"<<e->getSource()<<endl;
  }
}
